// Copyright (c) 2020 Presto Labs Pte. Ltd.
// Author: leon

#pragma once

#include <iomanip>
#include <sstream>
#include <string>

#include "coin2/base/time.h"
#include "coin2/exchange/feed.pb.h"
#include "coin/proto/coin_order_enums.pb.h"

struct LiquidationOrder {
  using OrderType = coin::proto::OrderType;
  using OrderSide = coin::proto::OrderSide;
  using OrderDuration = coin::proto::OrderDuration;
  using OrderState = coin::proto::OrderState;

  int64_t timestamp;
  double price;
  double qty;
  double avg_price;  // average price for filled part
  double fill_qty;   // qty already filled
  OrderType order_type;
  OrderSide order_side;
  OrderDuration order_duration;
  OrderState order_state;
  bool has_more_liquidation_order;
  std::string order_id;

  void Clear() {
    timestamp = 0;
    price = 0;
    qty = 0;
    avg_price = 0;
    fill_qty = 0;
    order_type = OrderType::UNKNOWN_ORDER_TYPE;
    order_side = OrderSide::UNKNOWN_ORDER_SIDE;
    order_duration = OrderDuration::GTC_ORDER;
    order_state = OrderState::CREATED_ORDER;
    has_more_liquidation_order = false;
    order_id = "";
  }

  double sign() const {
    if (order_side == OrderSide::BUY_ORDER ||
        order_side == OrderSide::BUY_OPEN_ORDER ||
        order_side == OrderSide::BUY_CLOSE_ORDER) {
      return 1;
    } else if (order_side == OrderSide::SELL_ORDER ||
               order_side == OrderSide::SELL_OPEN_ORDER ||
               order_side == OrderSide::SELL_CLOSE_ORDER) {
      return -1;
    } else {
      throw std::runtime_error("uninit trade side");
    }
  }

  double signed_qty() const {
    if (order_side == OrderSide::BUY_ORDER ||
        order_side == OrderSide::BUY_OPEN_ORDER ||
        order_side == OrderSide::BUY_CLOSE_ORDER) {
      return fill_qty;
    } else if (order_side == OrderSide::SELL_ORDER ||
               order_side == OrderSide::SELL_OPEN_ORDER ||
               order_side == OrderSide::SELL_CLOSE_ORDER) {
      return -fill_qty;
    } else {
      throw std::runtime_error("uninit trade side");
    }
  }
};

inline std::ostream& operator<<(
    std::ostream& os,
    const LiquidationOrder& liquidation_order) {
  using OrderSide = coin::proto::OrderSide;

  os << "Liquidation Order";
  os << "(price=";
  os << std::setw(15);
  os << liquidation_order.price;
  os << ",qty=";
  os << std::setw(15);
  os << liquidation_order.qty;
  os << ",fill_qty=";
  os << std::setw(15);
  os << liquidation_order.fill_qty;
  os << ",side=";
  if (liquidation_order.order_side == OrderSide::BUY_ORDER ||
      liquidation_order.order_side == OrderSide::BUY_OPEN_ORDER ||
      liquidation_order.order_side == OrderSide::BUY_CLOSE_ORDER) {
    os << "BUY";
  } else if (liquidation_order.order_side == OrderSide::SELL_ORDER ||
             liquidation_order.order_side == OrderSide::SELL_OPEN_ORDER ||
             liquidation_order.order_side == OrderSide::SELL_CLOSE_ORDER) {
    os << "SELL";
  } else {
    os << "UNKNOWN";
  }
  os << ",order_id=";
  os << std::setw(40);
  os << liquidation_order.order_id;
  os << ")";
  return os;
}
